package com.xc58.highreactor.seril;

import static com.xc58.highreactor.util.ByteUtil.getByteFormInt;
import static com.xc58.highreactor.util.ByteUtil.toInt;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Array;

import com.xc58.highreactor.exception.ParseDataException;
import com.xc58.highreactor.util.ByteUtil;

@SuppressWarnings({"rawtypes"})
public class ArraySerializer implements ISerializer<Object> {
	private static final byte[] ZERO = new byte[]{0,0,0,0};
	
	private static final StringSerializer SERIALIZER = new StringSerializer(); 
	
	public byte[] serialize(Object bak) throws Exception {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		Class comType = bak.getClass().getComponentType();
		out.write(SERIALIZER.serialize(comType.getName()));
		byte[] blen = getByteFormInt(Array.getLength(bak));
		if(comType.isPrimitive()){
			blen[3] = (byte) (blen[3] | (byte)0x80);
		}
		out.write(blen);
		
		for (int i =0 ; i< Array.getLength(bak); i ++) {
			Object raw = Array.get(bak, i);
			if(raw == null){
				out.write(ZERO);
				continue;
			}
			int type = SerialMatcher.getClassFlag(raw.getClass());
			byte[] serial = SerialMatcher.serializer(type, raw);
			if(type != -1){
				out.write(ByteUtil.getByteFormInt(type));
			}
			out.write(serial);
		}
		byte[] result = out.toByteArray();
		out.close();
		return result;
	}

	public Object deserialize(InputStream input) throws Exception {
		Object result = null;
		int length = 0;
		String className = SERIALIZER.deserialize(input);
		byte[] blength = new byte[4];
		if(input.read(blength) < 4){
			throw new ParseDataException();
		}
		byte flag = (byte) (blength[3] & 0x80);
		if(flag == (byte)0x80){
			blength[3] = (byte) (blength[3] & 0x7F);
			length = toInt(blength);
			if(className.length() == 3){
				className = "Integer";
			}else{
				className = firstLetterToUpper(className);
			}
			className = "java.lang." + className;
			result = Array.newInstance((Class)Class.forName(className).getField("TYPE").get(null), length);
		}else{
			length = toInt(blength);
			result = Array.newInstance(Class.forName(className), length);
		}
		
		
		
		for (int i = 0; i < length; i++) {
			byte[] btype = new byte[4];
			input.read(btype);
			int type = ByteUtil.toInt(btype);
			if(type == 0){
				Array.set(result, i, null);
				continue;
			}
			Object cur = SerialMatcher.deserializer(type,input);
			Array.set(result, i, cur);
		}
		
		return result;
	}
	
	private String firstLetterToUpper(String str){
        char[] array = str.toCharArray();
        array[0] -= 32;
        return String.valueOf(array);
    }
}
